package com.gzj.environment.server;

import com.gzj.environment.constant.CollectDataConstant;
import com.gzj.environment.module.collectData.context.ClientContext;
import com.gzj.environment.module.collectData.service.HandlerMessageService;
import com.gzj.environment.module.collectData.properties.NetworkProperties;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@ChannelHandler.Sharable
@EnableConfigurationProperties(NetworkProperties.class)
public class ReceiveDataHandler extends SimpleChannelInboundHandler<String> {

    private static final Map<String, Integer> idleMap = new ConcurrentHashMap<>();

    @Autowired
    private HandlerMessageService collectDataService;

    @Autowired
    private NetworkProperties networkProperties;

    /**
     * 接收客户端发过来的数据
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        String ip = ctx.channel().remoteAddress().toString();
        if (networkProperties.getBeatInfo().equals(msg)) {
            log.info("收到来自{}客户端的心跳包", ip);
        } else {
            // 获取消息的类型。现阶段的类型可能为连接、指标和命令
            String messageType = this.getMessageType(msg);
            // 处理消息
            collectDataService.handle(messageType, ctx, msg);
        }
    }

    /**
     * 根据消息的内容获取消息的类型
     * @param msg 消息的内容
     * @return
     */
    private String getMessageType(String msg) {
        if (msg.startsWith(networkProperties.getConnectMessagePrefix())) {
            return CollectDataConstant.MESSAGE_TYPE_IS_CONNECT;
        }
        if (msg.startsWith(networkProperties.getIndicatorMessagePrefix())) {
            return CollectDataConstant.MESSAGE_TYPE_IS_INDICATOR;
        }
        if (msg.startsWith(networkProperties.getVersionMessagePrefix())) {
            return CollectDataConstant.MESSAGE_TYPE_IS_VERSION;
        }
        return CollectDataConstant.MESSAGE_TYPE_IS_COMMAND;
    }

    /**
     * 当没有再规定的时间内收到心跳包会执行的逻辑
     * 进行超时处理
     * @param ctx 客户端channel的上下文
     * @param evt 事件对象
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        Channel channel = ctx.channel();
        String ip = channel.remoteAddress().toString();
        IdleStateEvent event = (IdleStateEvent) evt;

        // 非读空闲不进行操作
        if (!event.state().equals(IdleState.READER_IDLE)) {
            return;
        }

        // 计算每次超时后，一共超时了多少次
        Integer idleCount = idleMap.get(ip);
        if (idleCount == null) {
            idleCount = 1;
        } else {
            idleCount++;
        }
        log.info("客户端{}出现读空闲，总计读空闲次数为{}", ip, idleCount);
        if (idleCount == 3) {
            log.info("客户端{}出现的读空闲次数超过3次，关闭连接，释放更多资源", ip);
            ctx.channel().close();
            idleMap.remove(ip);
            ClientContext.removeClient(ctx);
            return;
        }

        idleMap.put(ip, idleCount);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.error("=== " + ctx.channel().remoteAddress() + " is active ===");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("=== " + ctx.channel().remoteAddress() + " error, cause: {} ===", cause.getMessage(), cause);
    }
}